<template>
  <div>
    <Draggable :component-data="{ tag: 'ul', name: 'flip-list', type: 'transition' }"
               :list="modelValue"
               class="el-upload-list el-upload-list--picture-card"
               item-key="orderNum"
               tag="transition-group"
               v-bind="dragOptions">
      <template #item="{ element: item, index }">
        <li class="el-upload-list__item">
          <!-- 图片展示 -->
          <img :src="item.content" alt="" class="el-upload-list__item-thumbnail">
          <!-- 图片操作 -->
          <span class="el-upload-list__item-actions">
            <!-- 图片预览 -->
            <span class="el-upload-list__item-preview" @click="handlePreviewFun(item)">
               <el-icon><ZoomIn/></el-icon>
            </span>
            <!-- 图片删除 -->
            <span v-if="showDelete && !disabled" class="el-upload-list__item-delete" @click="handleDeleteFun(item)">
               <el-icon><Delete/></el-icon>
            </span>
          </span>
        </li>
      </template>
    </Draggable>

    <template v-if="!disabled">
      <!-- 上传区域 -->
      <el-upload :accept="fileType.join(',')"
                 :action="serverUpload ? uploadUrl : uploadData.actionUrl"
                 :before-upload="beforeImageUpload"
                 :class="['upload', drag ? 'no-border' : '']"
                 :data="serverUpload ? {} : uploadData.requestData"
                 :disabled="disabled || percentageShow"
                 :drag="drag"
                 :headers="serverUpload ? uploadHeaders : {}"
                 :limit="limit"
                 :multiple="true"
                 :name="fileName"
                 :on-error="handleUploadError"
                 :on-exceed="handleUploadExceed"
                 :on-progress="handleUploadProgress"
                 :on-success="handleUploadSuccess"
                 :show-file-list="false">

        <!-- 上传进度 -->
        <el-progress v-if="percentageShow" :color="percentageColors" :percentage="percentage" :width="percentageWidth" type="circle"/>

        <!-- 上传操作 -->
        <template v-else>
          <SvgIcon icon="ep:plus"/>
        </template>

      </el-upload>

      <!-- 提示信息 -->
      <div v-if="showTip" class="el-upload__tip">
        <span>{{ uploadTip }}</span>
      </div>
    </template>

    <!-- 预览 -->
    <el-image-viewer v-if="viewerShow" :initial-index="imageIndex" :url-list="imageUrls" @close="handleViewerClose"/>
  </div>

</template>

<script lang="ts" setup>
import { computed, PropType, ref, watchEffect } from 'vue';
import { Delete, ZoomIn } from '@element-plus/icons-vue';
import { getToken, getTokenHeader } from '@/utils/auth.ts';
import { getRequestUrl } from '@/utils/axios/axios-service.ts'
import Draggable from '@/components/vuedraggable/src/vuedraggable';
import useUpload, { UploadItemData } from '@/components/upload/src/use-upload.ts';
import { SvgIcon } from '@/components/icon';

defineOptions({name: 'UploadImageMultiple'});

// 接受父组件参数
const props = defineProps({
  modelValue: {
    type: Array as PropType<UploadItemData[]>,
    default: () => []
  },
  // 图片数量限制
  limit: {
    type: Number,
    default: 6
  },
  // 拖拽上传
  drag: {
    type: Boolean,
    default: true
  },
  // 是否禁用上传组件
  disabled: {
    type: Boolean,
    default: false
  },
  // 是否显示提示信息
  showTip: {
    type: Boolean,
    default: true
  },
  // 大小限制(MB)
  fileSize: {
    type: Number,
    default: 10
  },
  // 文件类型
  fileType: {
    type: Array as PropType<string[]>,
    default: () => ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/bmp']
  },
  // 组件高度
  height: {
    type: String,
    default: '88px'
  },
  // 组件宽度
  width: {
    type: String,
    default: '88px'
  },
  // 组件边框圆角
  borderRadius: {
    type: String,
    default: '6px'
  },
  // 是否显示删除按钮
  showDelete: {
    type: Boolean,
    default: false
  },
  // 是否服务端上传
  serverUpload: {
    type: Boolean,
    default: false
  },
  fileName: {
    type: String,
    default: 'file'
  },
  // 图标保存到七牛云的路径
  uploadPath: {
    type: String,
    default: 'uploads'
  },
  // 是否重命名图片名称
  rename: {
    type: Boolean,
    default: true
  },
  // 图片类型
  imageType: {
    type: Number,
    default: 0
  },
});

// 服务端上传地址
const uploadUrl = ref(getRequestUrl('/sys/oss/upload'));
// 服务端上传头部
const uploadHeaders = computed(() => {
  let headers = {};
  let header = getTokenHeader();
  if (header) {
    headers[header] = getToken();
  }
  return headers;
});

// 可接受的文件类型
const acceptTypes = computed(() => {
  let accepts = props.fileType || []
  let types: string[] = []
  for (let item of accepts) {
    types.push(item.split('/')[1])
  }
  return types.join(' / ');
});

const dragOptions = computed(() => {
  return {
    animation: 600,
    disabled: props.disabled,
  }
});

const uploadTip = computed(() => {
  if (props.showTip) {
    let tipList: string[] = []
    if (acceptTypes.value) {
      tipList.push(`只能上传 ${acceptTypes.value} 文件`)
    }
    if (props.fileSize && props.fileSize > 0) {
      tipList.push(`且不超过 ${props.fileSize}MB`)
    }
    if (props.limit && props.limit > 0) {
      tipList.push(`最大只能上传 ${props.limit} 张图片`)
    }
    return tipList.join('，') + '。';
  }
  return ''
});

// 图片预览
const viewerShow = ref(false);
const imageUrls = ref<string[]>([]);
const imageIndex = ref(-1);
const handlePreviewFun = (item: UploadItemData) => {
  let index = props.modelValue.indexOf(item)

  if (index == -1) return
  imageIndex.value = index

  let urls: string[] = []
  props.modelValue.forEach(it => urls.push(it.content))
  imageUrls.value = urls
  viewerShow.value = true
};

// 图片预览关闭
const handleViewerClose = () => {
  viewerShow.value = false
  imageIndex.value = -1
  imageUrls.value = []
};

// 删除图片
const handleDeleteFun = (item: UploadItemData) => {
  let tempFileList = props.modelValue
  let index = tempFileList.indexOf(item)
  tempFileList.splice(index, 1)
};

// 上传进度宽度处理
const percentageWidth = computed(() => {
  return parseInt(props.width.replace('px', '')) - 10;
});

const {
  uploadData, uploadOptions, percentage, percentageShow, percentageColors,
  beforeImageUpload, handleUploadSuccess, handleUploadExceed, handleUploadError, handleUploadProgress
} = useUpload(props.modelValue, (url: string) => {
  // 生成上传成功的数据
  let newData: UploadItemData = {
    id: undefined,
    content: url,
    type: props.imageType,
    orderNum: Date.now(),
  }
  // 添加到列表
  props.modelValue.push(newData)
});

// watchEffect监听
watchEffect(() => {
  uploadOptions.limit = props.limit;
  uploadOptions.fileSize = props.fileSize;
  uploadOptions.fileTypes = props.fileType;
  uploadOptions.uploadPath = props.uploadPath;
  uploadOptions.rename = props.rename;
  uploadOptions.serverUpload = props.serverUpload;
});
</script>

<style lang="scss" scoped>
.el-upload-list--picture-card .el-upload-list__item-thumbnail {
  width: 100%;
  height: initial !important;
}

.el-upload-list--picture-card .el-upload-list__item {
  vertical-align: top;
  border: 1px dashed var(--el-border-color-darker);
  width: v-bind(width);
  height: v-bind(height);
}

.no-border {
  :deep(.el-upload) {
    border: none !important;
  }
}

:deep(.disabled) {
  .el-upload,
  .el-upload-dragger {
    cursor: not-allowed !important;
    background: var(--el-disabled-bg-color);
    border: 1px dashed var(--el-border-color-darker) !important;

    &:hover {
      border: 1px dashed var(--el-border-color-darker) !important;
    }
  }
}

.upload {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  cursor: pointer;
  outline: none;
  vertical-align: top;
}

:deep(.upload) {
  .no-border {
    :deep(.el-upload) {
      border: none !important;
    }
  }

  .el-upload {
    width: v-bind(width);
    height: v-bind(height);
    border-radius: v-bind(borderRadius);
    border: 1px dashed var(--el-border-color-darker);

    &:hover {
      border: 1px dashed var(--el-color-primary);
    }

    .el-upload-dragger {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 100%;
      height: 100%;
      padding: 0;
      overflow: hidden;
      background-color: transparent;
      border: 1px dashed var(--el-border-color-darker);
      border-radius: v-bind(borderRadius);

      &:hover {
        border: 1px dashed var(--el-color-primary);
      }
    }

    .el-upload-dragger.is-dragover {
      background-color: var(--el-color-primary-light-9);
      border: 1px dashed var(--el-color-primary) !important;
    }
  }
}

.el-upload__tip {
  line-height: 18px;
  color: var(--el-text-color-regular);
}

.el-upload-list__item-actions {
  font-size: 16px;
}

.el-upload-list__item-actions span + span {
  margin-left: 8px;
}

</style>
